package core.lib.network;

import java.util.LinkedList;

import core.lib.CoreConstants;
import core.lib.interfaces.ProtocolThreadManager;
import core.lib.model.CoreRequest;
import core.lib.tools.CoreLog;

/**
 * <p>
 * <code>ConnectionThread</code>类是为具体的网络连接线程提供获取<code>ConnectionRequest</code>，然后执行，返回结果这个处理逻辑的父类。<br>
 * 它不负责具体的连接工作（建立连接，发送、接收数据，返回数据，重试等，因为这些逻辑的顺序对于不同的连接类型是不一样的）。
 * </p>
 * 
 * @author <a href="mailto:cu2oh2co3@263.net">Ryan</a>
 */
public abstract class BaseProtocolThread extends Thread
{
	public static final int TASK_SUCCEEDED = 0;
	public static final int TASK_FAILED = 1;

	public static final int THREAD_STATE_OFF = 0;
	public static final int THREAD_STATE_ON = 1;
	public static final int THREAD_STATE_PAUSED = 2;

	private int m_state = THREAD_STATE_ON;
	private final BaseProtocolContext mContext;
	private final ProtocolThreadManager mManager;

	private LinkedList<BaseProtocolRequest> mRequestPool = new LinkedList<>();

	public BaseProtocolThread(ProtocolThreadManager manager, BaseProtocolContext context)
	{
		if (context == null || manager == null)
		{
			throw new IllegalArgumentException("Available network module and connection request pool instance are required!~");
		}

		mContext = context;
		mManager = manager;

		start();
	}

	protected abstract boolean doPrepare(BaseProtocolContext context);

	protected abstract void doSendMessage(BaseProtocolRequest pr, int leftRetryTimes);

	/**
	 * 执行一个<code>ConnectionRequest</code>
	 * 
	 * @param cr
	 *            要执行的<code>ConnectionRequest</code>
	 * @return 是否成功执行
	 */
	protected synchronized void executeProtocolRequest(BaseProtocolRequest pr)
	{
		try
		{
			doSendMessage(pr, 3);
		}
		catch (SecurityException e)
		{
			setConnectionState(THREAD_STATE_PAUSED);
			pr.setResponseCode(CoreConstants.RequestReturnCode.NETWORK_FAILURE);
		}
		catch (Exception e)
		{
			CoreLog.log(CoreLog.LEVEL_ERROR, NetworkConstants.NETWORK_TAG, "", e);

			setConnectionState(THREAD_STATE_PAUSED);
			pr.setResponseCode(CoreConstants.RequestReturnCode.NETWORK_FAILURE);
		}
		catch (Error e)
		{
			CoreLog.log(CoreLog.LEVEL_ERROR, NetworkConstants.NETWORK_TAG, "", e);

			setConnectionState(THREAD_STATE_PAUSED);
			pr.setResponseCode(CoreConstants.RequestReturnCode.NETWORK_FAILURE);
		}
		mManager.onProtocolRequestFinished(pr);
	}

	/**
	 * 返回当前的状态。
	 * 
	 * @return THREAD_STATE_ON或者THREAD_STATE_OFF
	 */
	public synchronized int getThreadState()
	{
		return m_state;
	}

	public BaseProtocolContext getContext()
	{
		return mContext;
	}

	/**
	 * 重载<code>Thread</code>的run方法，完成取出<code>ConnectionRequest</code>、 请求网络并返回结果的功能。当状态被置为
	 * <code>THREAD_STATE_OFF</code>，即停止循环。
	 * 
	 * @see java.lang.Thread#run()
	 */
	public void run()
	{
		BaseProtocolRequest req = null;
		while (m_state != THREAD_STATE_OFF)
		{
			// 以自己作为线程锁，避免其他线程在修改此线程的状态
			synchronized (this)
			{
				if (m_state == THREAD_STATE_PAUSED)
				{
					try
					{
						// 如果线程被暂停，进入wait状态
						wait();
						continue;
					}
					catch (InterruptedException e)
					{
						continue;
					}
				}
			}

			try
			{
				// 如果有未处理完的ConnectionRequest，继续处理该ConnectionRequest
				if (req == null)
				{
					synchronized (mRequestPool)
					{
						if (mRequestPool.size() == 0)
						{
							mRequestPool.wait();
						}
						else
						{
							req = mRequestPool.pop();// TODO 头还是尾?
						}
					}
				}
				
				if (req == null)
				{
					continue;
				}

				// 在执行一个ConnectionRequest之前，初始化网络连接。
				// 如果已经初始化，这个方法应该直接返回true
				if (!doPrepare(mContext))
				{
					// 通知网络失败
					mManager.onProtocolRequestFailed(req);
					continue;
				}

				if (req != null)
				{
					// 如果取到了ConnectionRequest，则开始执行
					executeProtocolRequest(req);
				}
				req = null;
			}
			catch (Exception e)
			{
				req = null;
				CoreLog.log(CoreLog.LEVEL_ERROR, NetworkConstants.NETWORK_TAG, "", e);
			}
		}
	}

	/**
	 * 设置当前的状态
	 * 
	 * @param state
	 *            THREAD_STATE_ON或者THREAD_STATE_OFF
	 */
	protected synchronized void setConnectionState(int state)
	{
		if (m_state == state)
		{
			return;
		}

		m_state = state;

		if (state == THREAD_STATE_ON)
		{
			if (!isAlive())
			{
				start();
			}
			else
			{
				notify();
			}
		}
	}

	public void finalize()
	{
		m_state = THREAD_STATE_OFF;
		interrupt();
	}

	public abstract void handleProtocolRequest(BaseProtocolRequest req);

	protected void addProtocolRequest(BaseProtocolRequest preq)
	{
		if (preq != null)
		{
			synchronized (mRequestPool)
			{
				mRequestPool.add(preq);
				mRequestPool.notifyAll();
			}
		}
	}
}
